grammar Mson;

mson:   object
    |   array
    ;

object
    :   '{' pair (',' pair)* '}'
    |   '{' '}' // empty object
    ;
    
//value is array and array's value is object means pair's domainHeader is package
pair
    :   domainHeader ':' value   # DomainValue
    |   domainHeader ':' object  # DomainClass
    |   domainHeader ':' array   # DomainArray
    ;

array
    :   '[' value (',' value)* ']'       # ArrayValue
    |   '[' object (',' object)* ']'     # Package
    |   '[' array (',' array)* ']'       # ArrayArray
    ;

value
    :   domainName
    |   NUMBER
    |   'true'
    |   'false'
    |   'null'
    |   string
    |   decimal
    |   override
    ;

override
    : domainName '(' value (',' value)* ')'
    ; 

string
    : 'STRING' '(' (NUMBER)? ')'
    ;
    
decimal
    : 'DECIMAL' '(' NUMBER ',' NUMBER ')'
    ;

domainHeader
    : (COMMENT|LINE_COMMENT+)? domainName (type)?
    ;

type
    : '<' KEYWORD (',' KEYWORD)* '>'
    ;

domainName
	:	IDENTIFIER ('.' IDENTIFIER)*   # Id
    |   IDENTIFIER ('.' IDENTIFIER)* '[' ']'  # IdArray
    |   KEYWORD '[' ']'                # KeywordArray
    |   KEYWORD                        # Keyword
	;
	
KEYWORD
	:   [A-Z]+
	;
IDENTIFIER :  [A-Z] ([0-9a-zA-Z])*;

STRING :  '"' (ESC | ~["\\])* '"' ;

fragment ESC :   '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;

NUMBER
    :   '-'? INT '.' INT EXP?   // 1.35, 1.35E-9, 0.3, -4.5
    |   '-'? INT EXP            // 1e10 -3e4
    |   '-'? INT                // -3, 45
    ;

fragment INT :   '0' | [1-9] [0-9]* ; // no leading zeros
fragment EXP :   [Ee] [+\-]? INT ; // \- since - means "range" inside [...]

WS  :   [ \t\n\r]+ -> skip ;

COMMENT
    :   '/*' .*? '*/'
    ;

LINE_COMMENT
    :   '//' ~[\r\n]*
    ;